/*
 * Copyright (c) 2024 iSOFT INFRASTRUCTURE SOFTWARE CO., LTD.
 * easyAda is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#include <core/endpoint.h>
#include <core/schedule.h>
#include <caps/capability.h>
#include <caps/endpoint.h>
#include <uapi/errors.h>
#include <uapi/ipcbuffer.h>
#include <uapi/ipcops.h>

static inline void cap_ep_set_obj(capability_t *cap, endpoint_t *obj)
{
    assert(((unsigned long)obj & 0x3) == 0);

    cap_set_long_info(cap, (unsigned long)obj);
}

static inline unsigned int cap_ep_get_id(capability_t *cap)
{
    return (cap_get_short_info(cap) >> CAP_EP_ATTR_BIT_ID_BEGIN) & lowbitsmask(CAP_EP_ATTR_BIT_ID_WIDTH);
}

static inline void cap_ep_set_id(capability_t *cap, unsigned int id)
{
    cap_set_short_info(cap, id);
}

void cap_ep_init(capability_t *cap, endpoint_t *obj, unsigned int id)
{
    endpoint_get(obj);
    cap_basic_init(cap, CAP_EP);
    cap_ep_set_obj(cap, obj);
    cap_ep_set_id(cap, id);
}

void cap_ep_dispatcher(capability_t *cap, unsigned long tag, unsigned long m0, unsigned long m1, unsigned long m2,
                       unsigned long m3, unsigned long m4, unsigned long m5)
{
    endpoint_t *ep = cap_ep_get_obj(cap);

    switch (msgtag_get_op(tag)) {
        case CAP_EP_OP_SEND:
            tag = msgtag_set_id(tag, cap_ep_get_id(cap));
            endpoint_send(ep, tag, m0, m1, m2, m3, m4, m5, current());
            break;

        case CAP_EP_OP_RECV:
            endpoint_receive(ep, tag, current());
            break;

        case CAP_EP_OP_CALL:
            tag = msgtag_set_id(tag, cap_ep_get_id(cap));
            endpoint_call(ep, tag, m0, m1, m2, m3, m4, m5, current());
            break;

        case CAP_EP_OP_REPLY:
            endpoint_reply(ep, tag, m0, m1, m2, m3, m4, m5, current());
            break;

        case CAP_EP_OP_REPLY_WAIT:
            endpoint_reply_wait(ep, tag, m0, m1, m2, m3, m4, m5, current());
            break;

        case CAP_EP_OP_CANCEL:
            endpoint_cancel(ep);
            task_set_retcode(current(), ESUCCESS);
            break;

        case CAP_EP_OP_BIND:
            endpoint_bind(ep, current());
            break;

        case CAP_EP_OP_UNBIND:
            endpoint_unbind(ep, current());
            break;

        default:
            task_set_retcode(current(), ERR_TO_RETCODE(-ENOSYS));
            break;
    }
}
